package com.example.stringbufferlogger.Utils;

import com.example.stringbufferlogger.VO.ComparisonResult;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Json 字符串对比工具类
 */
public class JsonComparator {

    public static ComparisonResult compareJson(String json1, String json2, Set<String> ignoredFields) {
        ComparisonResult result = new ComparisonResult();
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode node1 = objectMapper.readTree(json2);
            JsonNode node2 = objectMapper.readTree(json1);

            compareNodes(node1, node2, ignoredFields, "", result);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorMessage("解析JSON时出错: " + e.getMessage());
        }
        return result;
    }
//
//
//
//    private static void compareNodes(JsonNode node1, JsonNode node2, Set<String> ignoredFields, String path, ComparisonResult result) {
//        if (node1.isObject() && node2.isObject()) {
//            Iterator<String> fieldNames1 = node1.fieldNames();
//            Iterator<String> fieldNames2 = node2.fieldNames();
//
//            Set<String> allFields = new HashSet<>();
//            while (fieldNames1.hasNext()) {
//                allFields.add(fieldNames1.next());
//            }
//            while (fieldNames2.hasNext()) {
//                allFields.add(fieldNames2.next());
//            }
//
//            for (String field : allFields) {
//                if (ignoredFields.contains(field)) {
//                    continue;
//                }
//                JsonNode child1 = node1.get(field);
//                JsonNode child2 = node2.get(field);
//                String newPath = path.isEmpty() ? field : path + "." + field;
//                if (child1 == null != (child2 == null)) {
//                    recordDifference(newPath, child1, child2, result);
//                } else if (child1 != null && child2 != null) {
//                    compareNodes(child1, child2, ignoredFields, newPath, result);
//                }
//            }
//        } else if (node1.isArray() && node2.isArray()) {
//            int size1 = node1.size();
//            int size2 = node2.size();
//            if (size1 != size2) {
//                recordDifference(path, node1, node2, result);
//            }
//            for (int i = 0; i < Math.min(size1, size2); i++) {
//                JsonNode element1 = node1.get(i);
//                JsonNode element2 = node2.get(i);
//                String newPath = path + "[" + i + "]";
//                compareNodes(element1, element2, ignoredFields, newPath, result);
//            }
//        } else {
//            if (!node1.equals(node2)) {
//                recordDifference(path, node1, node2, result);
//            }
//        }
//    }
//
    private static void recordDifference(String path, JsonNode oldNode, JsonNode newNode, ComparisonResult result) {
        Map<String, Object> difference = new LinkedHashMap<>();
        difference.put("oldRes", oldNode != null ? oldNode.toString() : null);
        difference.put("newRes", newNode != null ? newNode.toString() : null);
        result.getDifferences().put(path, difference);
    }


    private static void compareNodes(JsonNode node1, JsonNode node2, Set<String> ignoredFields,
                                     String path, ComparisonResult result) {
        if (node1.isObject() && node2.isObject()) {
            // 对象比较逻辑保持不变
            handleObjectNodes(node1, node2, ignoredFields, path, result);
        } else if (node1.isArray() && node2.isArray()) {
            // 新的数组比较逻辑
            handleArrayNodes(node1, node2, path, result);
        } else {
            // 基本类型比较逻辑保持不变
            if (!node1.equals(node2)) {
                recordDifference(path, node1, node2, result);
            }
        }
    }

    /**
     * 处理数组类型节点比较
     */
    private static void handleArrayNodes(JsonNode array1, JsonNode array2,
                                         String path, ComparisonResult result) {
        // 转换为可修改的集合
        List<JsonNode> list1 = new LinkedList<>();
        array1.forEach(list1::add);
        List<JsonNode> list2 = new LinkedList<>();
        array2.forEach(list2::add);

        // 第一阶段：精确匹配并排除相同元素
        matchAndRemoveIdenticalElements(list1, list2);

        // 第二阶段：记录剩余差异
        if (!list1.isEmpty() || !list2.isEmpty()) {
            ArrayNode diff1 = createArrayNode(list1);
            ArrayNode diff2 = createArrayNode(list2);
            recordDifference(path, diff1, diff2, result);
        }
    }

    /**
     * 匹配并移除完全相同的元素（双重循环实现）
     */
    private static void matchAndRemoveIdenticalElements(List<JsonNode> list1,
                                                        List<JsonNode> list2) {
        Iterator<JsonNode> iter1 = list1.iterator();
        while (iter1.hasNext()) {
            JsonNode elem1 = iter1.next();
            Iterator<JsonNode> iter2 = list2.iterator();
            boolean found = false;

            while (iter2.hasNext()) {
                JsonNode elem2 = iter2.next();
                if (elem1.equals(elem2)) {
                    iter1.remove();
                    iter2.remove();
                    found = true;
                    break;
                }
            }

//            // 优化：找到匹配后立即跳出内层循环
//            if (found) {
//                break;
//            }
        }
    }

    /**
     * 创建包含剩余元素的ArrayNode
     */
    private static ArrayNode createArrayNode(List<JsonNode> elements) {
        ArrayNode array = JsonNodeFactory.instance.arrayNode();
        elements.forEach(array::add);
        return array;
    }

    /**
     * 处理对象类型节点比较（原逻辑保持不变）
     */
    private static void handleObjectNodes(JsonNode obj1, JsonNode obj2,
                                          Set<String> ignoredFields,
                                          String path, ComparisonResult result) {
        Set<String> allFields = new HashSet<>();
        obj1.fieldNames().forEachRemaining(allFields::add);
        obj2.fieldNames().forEachRemaining(allFields::add);

        for (String field : allFields) {
            if (ignoredFields.contains(field)) continue;

            JsonNode child1 = obj1.get(field);
            JsonNode child2 = obj2.get(field);
            String newPath = path.isEmpty() ? field : path + "." + field;

            if (child1 == null || child2 == null) {
                recordDifference(newPath, child1, child2, result);
            } else {
                compareNodes(child1, child2, ignoredFields, newPath, result);
            }
        }
    }

    // 使用更高效的差异记录方式
//    private static void recordDifference(String path, JsonNode oldVal, JsonNode newVal, ComparisonResult result) {
//        result.getDifferences().put(path,
//                oldVal != null ? oldVal.deepCopy() : null,
//                newVal != null ? newVal.deepCopy() : null
//        );
//        result.getDifferences().put(path,
//                oldVal != null ? oldVal.deepCopy() : null,
//                newVal != null ? newVal.deepCopy() : null
//        );
//    }
    public static void main(String[] args) {
        String json1 = "{\"ename\": \"John\",\"name\": \"John\", \"age\": 30, \"address\": {\"city\": \"New York\", \"street\": \"123 Main St\"}, \"hobbies\": [{\"city\": \"New York\", \"street\": \"13 Main St\"}, {\"city\": \"New Yrk\", \"street\": \"123 Main St\"}]}";
        String json2 = "{\"name\": \"John2\", \"age\": 30, \"address\": {\"city\": \"Nw York\", \"street\": \"456 Elm St\"}, \"hobbies\": [{\"city\": \"New York\", \"street\": \"123 Main St\"}, {\"city\": \"New York\", \"street\": \"13 Main St\"}]}";

        Set<String> ignoredFields = new HashSet<>();
        ignoredFields.add("age");
        ignoredFields.add("street");

        ComparisonResult result = compareJson(json1, json2, ignoredFields);
        if (result.isSuccess()) {
            if (!result.isDifferences()) {
                System.out.println("两个JSON对象相等");
            } else {
                System.out.println("两个JSON对象存在差异:");
                String str = result.getDifferencesStr();
                System.out.println(str);
                get(str);

            }

        } else {
            System.out.println("比较出错: " + result.getErrorMessage());
        }
    }

    public static void get(String json) {
//         json = "{\"ename\":{\"newString\":\"John\"},\"address.city\":{\"oldString\":\"Nw York\",\"newString\":\"New York\"},\"address.street\":{\"oldString\":\"456 Elm St\",\"newString\":\"123 Main St\"},\"hobbies[1].city\":{\"oldString\":\"New Yrk\",\"newString\":\"New York\"},\"hobbies[1].street\":{\"oldString\":\"13 Main St\",\"newString\":\"123 Main St\"},\"name\":{\"oldString\":\"John2\",\"newString\":\"John\"}}";

        try {
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode root = objectMapper.readTree(json);

            ObjectNode oldNode = objectMapper.createObjectNode();
            ObjectNode newNode = objectMapper.createObjectNode();

            Iterator<String> fieldNames = root.fieldNames();
            while (fieldNames.hasNext()) {
                String field = fieldNames.next();
                JsonNode subNode = root.get(field);
                if (subNode.isObject()) {
                    JsonNode oldValue = subNode.get("oldRes");
                    JsonNode newValue = subNode.get("newRes");

                    String[] parts = field.split("\\.");
                    ObjectNode currentOldNode = oldNode;
                    ObjectNode currentNewNode = newNode;

                    for (int i = 0; i < parts.length - 1; i++) {
                        String part = parts[i];
                        if (!currentOldNode.has(part)) {
                            currentOldNode.set(part, objectMapper.createObjectNode());
                        }
                        if (!currentNewNode.has(part)) {
                            currentNewNode.set(part, objectMapper.createObjectNode());
                        }
                        currentOldNode = (ObjectNode) currentOldNode.get(part);
                        currentNewNode = (ObjectNode) currentNewNode.get(part);
                    }

                    String lastPart = parts[parts.length - 1];
                    if (oldValue != null) {
                        currentOldNode.set(lastPart, oldValue);
                    }
                    if (newValue != null) {
                        currentNewNode.set(lastPart, newValue);
                    }
                }
            }

            String oldString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(oldNode);
            String newString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(newNode);

            String res = "oldString:\n" + oldString+"\nnewString:\n" + newString;
            System.out.println(res);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
